<template>
  <div>
    <div class="demo-input-suffix gl_searchBox">
      <el-row :gutter="20">
        <el-col :md="6" :lg="4">
          <p>角色名称</p>
          <el-input v-model="rolesQO.Filter" placeholder="请输入角色名称" clearable size="mini" @change="getPageData()" />
        </el-col>
        <el-col :md="6" :lg="4">
          <!-- <el-col :span="4"> -->
          <el-button style="margin-top:27px" type="primary" size="mini" @click="getPageData()">{{ $t('button.query') }}</el-button>
          <el-button style="margin-top:27px" type="warning" size="mini" @click="handleRefreshData">{{ $t('button.Reset') }}</el-button>
        </el-col>
      </el-row>
    </div>
    <el-row :gutter="20" class="gl_my_15">
      <el-col :md="6" :lg="4">
        <el-button type="success" size="mini" @click="handleOperateRoleRow('add')">新增角色</el-button>
      </el-col>
    </el-row>
    <el-table v-loading="loading" :data="tableData" size="mini" stripe>
      <el-table-column prop="displayName" label="角色名称" />
      <el-table-column :label="$t('search.creationDate')" width="200" align="center">
        <template slot-scope="{row}">
          <span v-if="row.creationTime">
            {{ row.creationTime | FormatDate('yyyy-MM-dd HH:mm:ss') }}
          </span>
        </template>
      </el-table-column>
      <el-table-column prop="creatorName" :label="$t('table.creator')" width="180" />
      <el-table-column :label="$t('table.description')" min-width="240">
        <template slot-scope="{row}">
          <el-popover placement="top-start" width="500" trigger="hover" :content="row.description">
            <span slot="reference" class="gl_ellipsis">{{ row.description }}</span>
          </el-popover>
        </template>
      </el-table-column>
      <el-table-column :label="$t('table.actions')" width="180">
        <template slot-scope="scope">
          <el-button type="text" size="mini" @click="handleOperateRoleRow('edit', scope.row)">{{ $t('button.edit') }}</el-button>
          <el-button type="text" size="mini" class="gl_color_error" @click="handleDeleteRole(scope.row)"><span class="gl_color_error">{{ $t('button.delete') }}</span></el-button>
        </template>
      </el-table-column>
    </el-table>
    <div align="center" class="gl_py_10">
      <el-pagination :current-page="rolesQO.Page" :page-size="rolesQO.MaxResultCount" :total="totalPage" layout="total,sizes,prev,pager,next,jumper" :page-sizes="[10, 20, 30, 40]" @size-change="sizeChange" @current-change="pageIndexChange" />
    </div>
    <!-- 新增/修改角色 -->
    <el-dialog :title="dialogAddRolesType === 'add' ? '新增角色' : '修改角色'" width="880px" class="gl_dialog_TitleLine" :close-on-click-modal="false" :visible.sync="dialogAddRoles">
      <el-scrollbar v-loading="dialogLoading" wrap-class="scrollbar-wrapper gl_dialog_height gl_mb_10">
        <el-form ref="refFormAddRole" label-width="120px" class="gl_px_10 gl_pb_15" :model="identityRoleCreateInput" :rules="formAddRoleVO_Rules" @submit.native.prevent>
          <el-row :gutter="20">
            <el-col :span="12">
              <el-form-item label="角色名称" prop="displayName" size="mini">
                <el-input v-model="identityRoleCreateInput.displayName" clearable placeholder="请输入角色名称" />
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item :label="$t('table.description')" size="mini">
                <el-input v-model="identityRoleCreateInput.description" clearable type="textarea" show-word-limit maxlength="200" placeholder="请输入描述信息" />
              </el-form-item>
            </el-col>
            <!-- v-if="userInfo.tenantId" -->
            <el-col v-if="userInfo.tenantId" :span="12">
              <el-form-item label="" label-width="" size="mini">
                <el-checkbox v-model="identityRoleCreateInput.includeChildOrganizationUnits">全部数据</el-checkbox>
              </el-form-item>
              <el-form-item class="data_range" label="数据范围" prop="organizationUnitIds" size="mini">
                <el-scrollbar ref="refOrgScroll" wrap-class="scrollbar-wrapper gl_dialog_height">
                  <el-tree
                    ref="refOrgTree"
                    :data="organizationUnitsTree"
                    show-checkbox
                    highlight-current
                    node-key="id"
                    :default-checked-keys="orgDefaultChecked"
                    :default-expanded-keys="orgDefaultChecked"
                    :props="orgDefaultProps"
                    class="tree_height"
                    :check-strictly="true"
                    @check-change="handleOrgCheckChange"
                  />
                  <el-select v-show="false" v-model="identityRoleCreateInput.organizationUnitIds" multiple />
                </el-scrollbar>
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item label="分配功能" prop="permissions" size="mini">
                <el-scrollbar ref="refPerScroll" wrap-class="scrollbar-wrapper gl_dialog_height">
                  <el-tree
                    ref="refPermissionTree"
                    v-model="identityRoleCreateInput.permissions"
                    :data="permissionList"
                    show-checkbox
                    default-expand-all
                    highlight-current
                    node-key="code"
                    :props="perDefaultProps"
                    :default-checked-keys="perDefaultChecked"
                    class="tree_height"
                    @check-change="handlePermissionCheckChange"
                  />
                </el-scrollbar>
              </el-form-item>
            </el-col>
          </el-row>
        </el-form>
      </el-scrollbar>
      <div slot="footer" class="dialog-footer">
        <el-button size="mini" @click="dialogAddRoles = false">{{ $t('button.cancel') }}</el-button>
        <el-button size="mini" type="primary" :loading="submitLoading" @click="handleSubmitRole">{{ $t('button.save') }}</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import { mapState } from 'vuex';
import { OidcMap, RouterMap } from '@/lib/form/mapData';
import { translateByCode } from '@/lib/getTransData';
import {
  Api_GET_RolesQO,
  IdentityRoleCreateInput
} from '@/lib/form/swaggerForm';
import { FormAddRoleVO_Rules } from '@/lib/validate/identity';
import {
  api_POST_Roles, // 新建角色
  api_DELETE_RolesId, // 删除角色
  api_PUT_RolesId, // 修改角色
  api_GET_Roles, // 获取角色列表
  api_GET_OrganizationUnitsTree // 获取组织结构树结构
} from '@/extend/api/swaggerApi/identity';
import { CopyData } from '@/lib';
export default {
  name: 'Roles',
  data() {
    return {
      orgDefaultProps: {
        children: 'children',
        label: (data, node) => {
          return data.displayName;
        }
      },
      perDefaultProps: {
        children: 'children',
        label: (data, node) => {
          return translateByCode(`route.${data.title}`);
        }
      },
      rolesQO: new Api_GET_RolesQO(),
      identityRoleCreateInput: new IdentityRoleCreateInput(),
      orgDefaultChecked: [],
      perDefaultChecked: [],
      totalPage: 0,
      tableData: [],
      tableRow: {},
      dialogAddRoles: false,
      dialogAddRolesType: '',
      loading: false,
      submitLoading: false,
      dialogLoading: false,
      organizationUnitsTree: [],
      authorityType: [],
      deleteCurrentCode: {},
      permissionList: [],
      formAddRoleVO_Rules: new FormAddRoleVO_Rules(),
      // 数据默认展开项
      dataDefaultExpandedKey: []
    };
  },
  computed: {
    ...mapState({
      addRoutes: state => state.permission.addRoutes,
      userInfo: state => state.user.info
    })
  },
  watch: {
    dialogAddRoles(val) {
      if (!val) {
        // 关闭
        this.identityRoleCreateInput = new IdentityRoleCreateInput();
        this.$refs['refFormAddRole'].resetFields();
        if (this.userInfo.tenantId) {
          // 处理回显延迟问题
          this.$nextTick(() => {
            this.$refs['refOrgTree'].setCheckedKeys([]);
            this.$refs['refPermissionTree'].setCheckedKeys([]);
          });
          // 处理滚动条返回顶部
          this.$refs['refOrgScroll'].wrap.scrollTop = 0;
          this.$refs['refPerScroll'].wrap.scrollTop = 0;
        }
      } else {
        // The page does not display, the default is false.
        this.identityRoleCreateInput.isPublic = false;
        this.identityRoleCreateInput.isDefault = false;
      }
    }
  },
  created() {
    this.getPageData();
  },
  methods: {
    // 重置
    handleRefreshData() {
      this.rolesQO = new Api_GET_RolesQO();
      this.getPageData();
    },
    // 获取表格数据
    getPageData(page) {
      this.loading = true;
      this.rolesQO.Page = page || 1;
      this.rolesQO.SkipCount = (this.rolesQO.Page - 1) * this.rolesQO.MaxResultCount;
      this.rolesQO.IncludeDetails = true;
      api_GET_Roles(this.rolesQO)
        .then(res => {
          this.tableData = res.items;
          this.totalPage = res.totalCount;
          this.loading = false;
        })
        .catch(() => {
          this.loading = false;
        });
    },
    sizeChange(MaxResultCount) {
      this.rolesQO.MaxResultCount = MaxResultCount;
      this.getPageData();
    },
    pageIndexChange(currentPage) {
      this.getPageData(currentPage);
    },
    // 弹框 —— 新增/编辑角色
    handleOperateRoleRow(type, row) {
      this.deleteCurrentCode = {};
      this.identityRoleCreateInput = new IdentityRoleCreateInput();
      this.orgDefaultChecked = [];
      this.perDefaultChecked = [];
      this.getOrganizationUnitsTree();
      console.log(row);
      if (type === 'edit') {
        CopyData(row, this.identityRoleCreateInput);
        // 编辑状态下回显数据范围，列表row字段为organizationUnits，提交字段为organizationUnitIds，故自行处理赋值
        this.identityRoleCreateInput.organizationUnitIds = [];
        const _organizationUnitIds = row.organizationUnits && row.organizationUnits.length && row.organizationUnits[0].id || '';
        this.identityRoleCreateInput.organizationUnitIds = _organizationUnitIds && [_organizationUnitIds] || [];
        this.orgDefaultChecked = this.identityRoleCreateInput.organizationUnitIds;
        // key value 值转换
        this.perDefaultChecked = [];
        const routerMap = new RouterMap();
        if (row.permissions && row.permissions.length > 0) {
          row.permissions.filter(item => {
            this.perDefaultChecked.push(
              routerMap[item] ? routerMap[item] : item
            );
          });
        }
      }
      // 根据左侧菜单处理功能列表
      this.permissionList = [];
      this.permissionList = this.processPermissionData(
        JSON.parse(JSON.stringify(this.addRoutes))
      );
      this.tableRow = row;
      this.dialogAddRolesType = type;
      this.dialogAddRoles = true;
      this.$nextTick(() => {
        this.$refs.refFormAddRole.clearValidate();
      });
    },
    // 获取数据范围(组织结构树)
    getOrganizationUnitsTree() {
      this.dialogLoading = true;
      api_GET_OrganizationUnitsTree()
        .then(res => {
          this.organizationUnitsTree = res.items.map(item => {
            item.isFirst = true;
            return item;
          });
          this.organizationUnitsTree = this.handleOrganizationUnitsTransfer(this.organizationUnitsTree);
          console.log(this.organizationUnitsTree);
          this.dialogLoading = false;
        })
        .catch(() => {
          this.dialogLoading = false;
        });
    },
    handleOrganizationUnitsTransfer(organizationUnitsTree) {
      const optionsOrganizationUnitsTransfer = [];
      for (let i = 0; i < organizationUnitsTree.length; i++) {
        const item = organizationUnitsTree[i];
        if (item.typeCode) {
          if (item.children) {
            item.children = this.handleOrganizationUnitsTransfer(item.children);
          }
          item.children = item.children.length ? item.children : null;
          optionsOrganizationUnitsTransfer.push(item);
        }
      }
      return optionsOrganizationUnitsTransfer;
    },
    handleOrgCheckChange(data, checked, node) {
      console.log(checked);
      if (checked === true) {
        this.checkedId = data.id;
        this.$refs.refOrgTree.setCheckedKeys([data.id]);
      } else {
        if (this.checkedId === data.id) {
          this.$refs.refOrgTree.setCheckedKeys([]);
        }
      }
      this.identityRoleCreateInput.organizationUnitIds = this.$refs.refOrgTree.getCheckedKeys();
    },
    handlePermissionCheckChange(data, checked, indeterminate) {
      this.identityRoleCreateInput.permissions = this.$refs.refPermissionTree.getCheckedKeys();
    },
    // 提交 —— 新增/编辑角色
    handleSubmitRole() {
      this.submitLoading = true;
      this.$refs['refFormAddRole'].validate(valid => {
        console.log(valid);
        if (valid) {
          console.log(1111);
          // deleteCurrentCode里面包含的不提交,只做显示用
          const _identityRoleCreateInput = JSON.parse(
            JSON.stringify(this.identityRoleCreateInput)
          );
          console.log(JSON.parse(JSON.stringify(_identityRoleCreateInput)));
          _identityRoleCreateInput.permissions = _identityRoleCreateInput.permissions.filter(
            item => item && !(item in this.deleteCurrentCode)
          );

          // key value 值转换
          const oidcMap = new OidcMap();
          const arr = [];
          _identityRoleCreateInput.permissions.filter(item => {
            arr.push(oidcMap[item] ? oidcMap[item] : item);
          });
          _identityRoleCreateInput.permissions = arr;

          // 与后台定的业务 —— 选中“消息中心”时需要添加上“AbpIdentity.OrganizationUnits.Get”
          let _relationRoles = [];
          // （1）组织管理、角色管理、客户管理、版本管理不显示获取、新增等二级按钮但是需要加这些功能（与产品沟通）
          // （2）选中赛事管理时，需要加上竞技模型"EventsManagement.Competitions.KyorugiSetting"设置权限
          const _addIdentityConfig = {
            'Chat.Messaging': ['AbpIdentity.OrganizationUnits.Get'],
            'AbpIdentity.OrganizationUnits': [
              'AbpIdentity.Users',
              'AbpIdentity.Users.Create',
              'AbpIdentity.Users.Update',
              'AbpIdentity.Users.Delete',
              'AbpIdentity.OrganizationUnits.Get',
              'AbpIdentity.OrganizationUnits.Create',
              'AbpIdentity.OrganizationUnits.Update',
              'AbpIdentity.OrganizationUnits.Delete'
            ],
            'AbpIdentity.Roles': [
              'AbpIdentity.OrganizationUnits.Get',
              'AbpIdentity.Roles.Create',
              'AbpIdentity.Roles.Update',
              'AbpIdentity.Roles.Delete'
            ],
            'Saas.Tenants': [
              'AbpIdentity.OrganizationUnits.Get',
              'Saas.Tenants.Create',
              'Saas.Tenants.Update',
              'Saas.Tenants.Delete'
            ],
            'Saas.Editions': [
              'Saas.Editions.Create',
              'Saas.Editions.Update',
              'Saas.Editions.Delete'
            ],
            'CMS.SystemManagement': [
              'CMS.SystemManagement',
              'CMS.SiteManagement',
              'CMS.SiteLogs',
              'CMS.ErrorLogs',
              'CMS.MessageManagement',
              'CMS.ColumnManagement',
              'CMS.ContentManagement',
              'CMS.AdManagement',
              'CMS.ApproveManagement',
              'CMS.RecycleBin',
              'CMS.GenerateManagement',
              'CMS.GenerateIndexPage',
              'CMS.TemplateManagement',
              'CMS.SiteTemplateManagement',
              'CMS.PageTemplateManagement',
              'CMS.ColumnTemplateManagement',
              'CMS.AdTemplateManagement',
              'CMS.AdPositionManagement'
            ],
            'Payment.Order': [
              'Payment.Order.Create',
              'Payment.Order.Update',
              'Payment.Order.Delete'
            ],
            'EventsManagement.Competitions': [
              'EventsManagement.Competitions.KyorugiSetting',
              'EventsManagement.ClerkOfCourse'
            ]
          };
          console.log(_identityRoleCreateInput.permissions);
          _relationRoles = this.addIdentityByChoose(
            _identityRoleCreateInput.permissions,
            _addIdentityConfig
          );
          _identityRoleCreateInput.permissions = [
            ...new Set(
              _identityRoleCreateInput.permissions.concat(_relationRoles)
            )
          ];
          _identityRoleCreateInput.includeDetails = false;
          if (this.dialogAddRolesType === 'add') {
            api_POST_Roles(_identityRoleCreateInput)
              .then(res => {
                this.submitLoading = false;
                this.dialogAddRoles = false;
                this.getPageData();
                this.$message({ type: 'success', message: '操作成功！' });
              }, error => {
                this.$message({ type: 'error', message: '操作失败！' + error.error.message });
                this.submitLoading = false;
              });
          }
          if (this.dialogAddRolesType === 'edit') {
            _identityRoleCreateInput.concurrencyStamp = this.tableRow.concurrencyStamp; // 修改信息需带上concurrencyStamp
            api_PUT_RolesId(this.tableRow.id, _identityRoleCreateInput)
              .then(res => {
                this.submitLoading = false;
                this.dialogAddRoles = false;
                this.getPageData(this.rolesQO.Page);
                this.$message({ type: 'success', message: '操作成功！' });
              }, error => {
                this.$message({ type: 'error', message: '操作失败！' + error.error.message });
                this.submitLoading = false;
              });
          }
        } else {
          this.submitLoading = false;
          return false;
        }
      });
    },
    // 根据当前选择的权限添加依赖权限
    addIdentityByChoose(identity, aData) {
      let returnData = [];
      for (const i in aData) {
        if (identity.includes(i)) {
          returnData = returnData.concat(aData[i]);
        }
      }
      return returnData;
    },
    // 角色删除
    handleDeleteRole(row) {
      this.$confirm(`您确定要删除 [${row.displayName}] 吗？`, '提示', {
        confirmButtonText: translateByCode('alert.confirm'),
        cancelButtonText: translateByCode('alert.cancel'),
        type: 'warning'
      }).then(() => {
        api_DELETE_RolesId(row.id).then(res => {
          this.getPageData();
          this.$message({ type: 'success', message: '操作成功！' });
        }, error => {
          this.$message({ type: 'error', message: '操作失败！' + error.error.message });
        });
      });
    },
    // 处理路由配置的权限控制
    processPermissionData(data) {
      const arr = [];
      for (let i = 0; i < data.length; i += 1) {
        const item = data[i];
        if (item.path !== '/') {
          if (item && item.meta) {
            item.title = item.meta.title;
            item.code = item.meta.code;

            if (item.meta.deleteThis) {
              continue;
            }
            if (!item.code) {
              console.log(
                `%c ${item.title}没有配置code，此code必须配置！`,
                'color: red'
              );
            }
            if (
              item.meta.deleteItem === undefined ||
              item.meta.allIdentity === undefined ||
              item.meta.deleteCode === undefined
            ) {
              console.log(
                '请检查allIdentity、deleteItem、deleteCode是否没配置！'
              );
            }
            // deleteItem: true 不显示本层，但如果有children，则要把children提上来替换掉本层
            if (item.meta.deleteItem) {
              if (item.children && item.children.length > 0) {
                data.splice(i + 1, 0, ...item.children);
              }
              continue;
            }
            // allIdentity: true 不渲染children
            if (item.meta.allIdentity) {
              delete item.children;
            }
            // deleteCode: true 不使用本层code
            if (item.meta.deleteCode) {
              this.deleteCurrentCode[item.code] = item.code;
            }
          }
          if (item.children && item.children.length > 0) {
            item.children = this.processPermissionData(item.children);
          }
          arr.push(item);
        }
      }
      console.log(arr);
      return arr;
    },
    // 根据ID查找树中的数据
    findTreeDataById(_id, _treeData) {
      for (let i = 0; i < _treeData.length; i++) {
        const item = _treeData[i];
        if (item.id === _id) {
          return item;
        }
        if (item.children && item.children.length) {
          const _data = this.findTreeDataById(_id, item.children);
          if (_data) {
            return _data;
          }
        }
      }
      return;
    }
  }
};
</script>
<style scoped>
.tree_height {
  height: 283px;
}
</style>
